package chloroform.oauth

import java.lang.String
import javax.servlet._
import http.{HttpSession, HttpServletResponse, HttpServletRequest}
import util.logging.Logged

import util.crypto.{RSASHA1Signer, RSAEncoder}
import com.google.gdata.client.authn.oauth.{OAuthRsaSha1Signer, GoogleOAuthHelper, GoogleOAuthParameters}
import com.google.gdata.client.docs.DocsService
import java.net.{URL, URLEncoder}
import com.google.gdata.data.docs.{DocumentListEntry, DocumentListFeed}

/**
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: 1.3.11
 * Time: 16:34
 * To change this template use File | Settings | File Templates.
 */

class OAuthFilter extends Filter with Logged {

  val signer = new RSASHA1Signer(classOf[OAuthFilter].
    getClassLoader.getResourceAsStream("chloroform/crypto/scaladuct-private.der"))
  val privKey = signer.privateKey
  val CONSUMER_KEY = "scaladuct.appspot.com"

  def init(p1: FilterConfig) = {}

  def doFilter(req: ServletRequest, resp: ServletResponse, chain: FilterChain) = {
    val httpReq = req.asInstanceOf[HttpServletRequest]
    val httpResp = resp.asInstanceOf[HttpServletResponse]
    val session: HttpSession = httpReq.getSession

    debug("Handling " + httpReq.getRequestURL)

    session.synchronized {

      val accessData = session.getAttribute(classOf[OAuthAccessTokenAndSecret].getName).asInstanceOf[OAuthAccessTokenAndSecret]
      if (accessData == null) {

        authorizeAccess(httpReq, httpResp)

      } else if (!accessData.isUpgraded) {

        upgradeAccessToken(httpReq, httpResp, accessData)

      } else {
        // Pass-through processing
        chain.doFilter(req, resp)
      }

    }
  }

  def authorizeAccess(httpReq: HttpServletRequest, httpResp: HttpServletResponse): Unit = {
    val session: HttpSession = httpReq.getSession

    val requestURL: String = httpReq.getRequestURL.toString
    var deferredURL = requestURL
    val query = httpReq.getQueryString
    if (query != null)
      deferredURL += "?" + query
    deferredURL = URLEncoder.encode(deferredURL, "US-ASCII")

    val redirectURL = requestURL

    val oauthParameters = new GoogleOAuthParameters
    oauthParameters.setOAuthConsumerKey(CONSUMER_KEY)
    oauthParameters.setScope("https://docs.google.com/feeds/")
    oauthParameters.setOAuthCallback(requestURL + "?deferred=" + deferredURL)

    val oauthHelper = new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
    oauthHelper.getUnauthorizedRequestToken(oauthParameters);

    val accessData: OAuthAccessTokenAndSecret = new OAuthAccessTokenAndSecret(CONSUMER_KEY, signer.encodedKey)
    accessData.install(session)

    val approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters)
    httpResp.sendRedirect(approvalPageUrl)
  }

  def upgradeAccessToken(httpReq: HttpServletRequest, httpResp: HttpServletResponse,
                         accessData: OAuthAccessTokenAndSecret): Unit = {
    val oauthParameters = new GoogleOAuthParameters
    oauthParameters.setOAuthConsumerKey(CONSUMER_KEY)

    val oauthHelper = new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
    oauthHelper.getOAuthParametersFromCallback(httpReq.getQueryString(), oauthParameters)

    val accessToken = oauthHelper.getAccessToken(oauthParameters)
    val accessTokenSecret = oauthParameters.getOAuthTokenSecret()
    accessData.upgrade(accessToken, accessTokenSecret)

    val session: HttpSession = httpReq.getSession
    accessData.install(session)

    var deferredURL = httpReq.getParameter("deferred")
    if (deferredURL == null)
      deferredURL = "/"

    debug("Redirecting to " + deferredURL)
    httpResp.sendRedirect(deferredURL)
  }

  def destroy = {}

}